---
sidebar_position: 4
---

import { HStack } from "@site/src/components/HStack";
import imperativeScrollVideo from "@site/static/videos/imperative-scroll.mp4";

# Tips and Tricks

## Exploring the libary and props

All props from Flash Calendar are documented and prefixed with `calendar` to
increase IDE discoverability. After installing the package, just type `<Calendar
calendar` and open your autocomplete to see the available options.

## Date IDs vs Dates

Date and timezones are a confusing topic. This is why Flash Calendar is careful to name things consistently. All props and callbacks used by the library follows the same convention of using a date ID instead of a `Date`.

Date ID is a simple `YYYY-MM-DD` representation of a given date. Flash Calendar exposes two functions to convert between Date and Date ID.

```tsx
import { toDateId, fromDateId } from "@marceloterreiro/flash-calendar";

const januaryFirstAsDate = fromDateId("2024-01-01"); // Date object
const januaryFirstAsId = toDateId(januaryFirstAsDate); // "2024-01-01"
```

It's **highly recommended to use `toDateId` and `fromDateId` when interacting with the library**. These functions were purposefully created to avoid timezones and other date-related issues.

For instance, consider this code:

```tsx
const endOfJanuary = new Date("2024-01-31");

// ❌ Don't do this, for some dates and timezones, this will return unexpected results
const endOfJanuaryId = endOfJanuary.toISOString().slice(0, 10); // 2024-02-01 or 2024-01-31, depending on the timezone
```

The code above is not completely safe. It can return `2024-02-01` for some timezones. Instead, use `toDateId`:

```tsx
const endOfJanuaryId = toDateId("2024-01-31");
const endOfJanuary = fromDateId(endOfJanuaryId); // Date object
```

These two convertions functions were [battle-tested](https://github.com/MarceloPrado/flash-calendar/blob/ee87cb1a695a42840f00f17bbaeb1a795a1e3ba0/packages/flash-calendar/src/helpers/dates.test.ts#L30-L130) to return the expected results, regardless of the timezone.

## Programmatically scrolling to a date

Flash Calendar exposes a `ref` that allows imperative scrolling to a desired
date (`.scrollToDate`), a month (`.scrollToMonth`), or an offset
(`.scrollToOffset`).

<HStack spacing={24} alignItems="flex-start">

<div>

```tsx
import { addMonths, subMonths, startOfMonth } from "date-fns";
import type { CalendarListRef } from "@marceloterreiro/flash-calendar";
import { Calendar, toDateId } from "@marceloterreiro/flash-calendar";
import { useRef, useState } from "react";
import { Button, Text, View } from "react-native";

export function ImperativeScrolling() {
  const [currentMonth, setCurrentMonth] = useState(startOfMonth(new Date()));
  const ref = useRef<CalendarListRef>(null);

  const onCalendarDayPress = useCallback((dateId: string) => {
    ref.current?.scrollToDate(fromDateId(dateId), true);
  }, []);

  return (
    <View style={{ paddingTop: 20, flex: 1 }}>
      <View style={{ flexDirection: "row", gap: 12 }}>
        <Button
          onPress={() => {
            const pastMonth = subMonths(currentMonth, 1);
            setCurrentMonth(pastMonth);
            ref.current?.scrollToMonth(pastMonth, true);
          }}
          title="Past month"
        />
        <Text>Current: {toDateId(currentMonth)}</Text>
        <Button
          onPress={() => {
            const nextMonth = addMonths(currentMonth, 1);
            setCurrentMonth(nextMonth);
            ref.current?.scrollToMonth(nextMonth, true);
          }}
          title="Next month"
        />
      </View>
      <View style={{ flex: 1, width: "100%" }}>
        <Calendar.List
          calendarInitialMonthId={toDateId(currentMonth)}
          onCalendarDayPress={onCalendarDayPress}
          ref={ref}
        />
      </View>
    </View>
  );
}
```

</div>

<video controls width={250}>
  <source src={imperativeScrollVideo} type="video/mp4" />
</video>

</HStack>

You can also pass an `additionalOffset` to fine-tune the scroll position:

```tsx
.scrollToDate(fromDateId("2024-07-01"), true, { additionalOffset: 4 })
```

## Setting Border Radius to `Calendar.Item.Day`

To apply a border radius to the `Calendar.Item.Day` component, it's necessary to
specify the radius for all four corners. Here's an example of how to achieve
this:

```tsx
itemDay: {
  base: () => ({
    container: {
      borderTopRightRadius: 10,
      borderBottomRightRadius: 10,
      borderTopLeftRadius: 10,
      borderBottomLeftRadius: 10,
    },
  }),
}
```

## Avoiding dark mode

If your app doesn't support dynamic themes, you can override Flash Calendar's
color scheme by passing a `calendarColorScheme` prop:

```tsx
export const LightModeOnly = () => {
  const { calendarActiveDateRanges, onCalendarDayPress } = useDateRange({
    startId: "2024-02-04",
    endId: "2024-02-09",
  });

  return (
    <Calendar
      calendarActiveDateRanges={calendarActiveDateRanges}
      calendarColorScheme="light"
      calendarMonthId={toDateId(startOfThisMonth)}
      onCalendarDayPress={onCalendarDayPress}
    />
  );
};
```

When set, Flash Calendar's theming system will use this scheme instead of the
user system's theme.

**Note**: you should avoid using this prop. Instead, your app should
support dynamic themes that react to the user's system preferences. The prop is
provided as an escape hatch for apps that doesn't support dynamic themes yet.

## Listening to the visible months

You can listen to which months are currently visible by hooking into the [`onViewableItemsChange`](https://shopify.github.io/flash-list/docs/usage#onviewableitemschanged) prop:

```tsx
export const ListenToVisibleMonth = () => {
  const [selectedDate, setSelectedDate] = useState(today);
  const [visibleMonth, setVisibleMonth] = useState(today);

  const handleViewableItemsChanged = useCallback<
    NonNullable<FlashListProps<CalendarMonth>["onViewableItemsChanged"]>
  >(({ viewableItems }) => {
    const firstVisibleItem = viewableItems.find((item) => item.isViewable);

    if (firstVisibleItem) {
      setVisibleMonth(firstVisibleItem.item.id);
    }
  }, []);

  return (
    <View style={{ flex: 1, gap: 24 }}>
      <View style={{ gap: 12 }}>
        <Text>Selected date: {selectedDate}</Text>
        <Text>Visible month: {visibleMonth}</Text>
      </View>
      <Calendar.List
        calendarActiveDateRanges={[{ startId: today, endId: today }]}
        calendarInitialMonthId="2024-11-01"
        onCalendarDayPress={setSelectedDate}
        onViewableItemsChanged={handleViewableItemsChanged}
      />
    </View>
  );
};
```
